package orm.er;

import orm.infrastructure.interfaces.IAssignable;
import orm.infrastructure.interfaces.IBinarySerialize;
import orm.infrastructure.interfaces.INullable;
import orm.infrastructure.interfaces.IValidable;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

/**
 * Created with IntelliJ IDEA.
 * User: Awake
 * Date: 03.05.12
 * Time: 10:33
 * To change this template use File | Settings | File Templates.
 */
public class AddressMock implements IAssignable, IValidable, INullable, IBinarySerialize, Cloneable {


    private static final int ADDRESS_LENGTH = 100;
    private static final String NULL_EXCEPTION = "Can not operate with null object";
    private static final String NOT_VALID_EXCEPTION = "Can not operate with not valid object";
    private static final String ENCODING = "UTF-16";
    private static final int NULL_VALUE = -1;

    public AddressMock() {

    }

    public AddressMock(int addressID, int personID, String address) {
        this.m_addressID = addressID;
        this.m_personID = personID;
        this.m_address = address;
        this.m_nullable = false;

    }

    /**
     * Creates nullable instance of AddressMock
     *
     * @return nullable AddressMock object
     */

    public static AddressMock getNullableInstance() {
        AddressMock addressMock = new AddressMock();
        addressMock.m_nullable = true;
        return addressMock;
    }

    /**
     * (Non - JavaDoc)
     *
     * @see orm.infrastructure.interfaces.IAssignable#assignTo(Object)
     */

    @Override
    public void assignTo(Object object) {

        if (object != null && object.getClass().equals(AddressMock.class)) {

            AddressMock address = (AddressMock) object;
            address.setAddressID(this.m_addressID);
            address.setPersonID(this.m_personID);
            address.setAddress(this.m_address);
        }
    }

    /**
     * Makes clone of existing object
     *
     * @return cloned object
     */

    @Override
    public Object clone() {
        AddressMock address = new AddressMock();
        this.assignTo(address);
        return address;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof AddressMock)) return false;

        AddressMock that = (AddressMock) o;

        if (m_addressID != that.m_addressID) return false;
        if (m_personID != that.m_personID) return false;
        if (m_address != null ? !m_address.equals(that.m_address) : that.m_address != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = m_addressID;
        result = 31 * result + m_personID;
        result = 31 * result + (m_address != null ? m_address.hashCode() : 0);
        return result;
    }

    /**
     * @see orm.infrastructure.interfaces.IBinarySerialize#writeTo(java.io.DataOutputStream)
     */

    @Override
    public void writeTo(DataOutputStream outputStream) throws IOException {

        if (!this.Validate()) {
            throw new UnsupportedOperationException(NOT_VALID_EXCEPTION);
        } else {

            outputStream.writeInt(getAddressID());
            outputStream.writeInt(getPersonID());
            if (m_address == null) {
                outputStream.writeInt(NULL_VALUE);
            } else {
                byte[] addressBinaryArray = getAddress().getBytes(ENCODING);
                outputStream.writeInt(addressBinaryArray.length);
                outputStream.write(addressBinaryArray);
            }
        }
    }

    /**
     * @see orm.infrastructure.interfaces.IBinarySerialize#readFrom(java.io.DataInputStream)
     */

    @Override
    public void readFrom(DataInputStream inputStream) throws IOException {

        if (this.m_nullable) {
            throw new UnsupportedOperationException(NULL_EXCEPTION);
        } else {

            setAddressID(inputStream.readInt());
            setPersonID(inputStream.readInt());
            int addressLength = inputStream.readInt();
            if (addressLength >= 0) {
                byte[] addressBytes = new byte[addressLength];
                inputStream.read(addressBytes, 0, addressLength);
                String address = new String(addressBytes, ENCODING);
                setAddress(address);
            } else {
                setAddress(null);
            }
        }
    }

    /**
     * @see orm.infrastructure.interfaces.INullable#isNullable()
     */

    @Override
    public boolean isNullable() {
        return m_nullable;
    }

    @Override
    public boolean Validate() {
        return !(this == null || m_addressID < 0 || m_personID < 0 || m_address == null || m_nullable);
    }

    public int getAddressID() {
        return m_addressID;
    }

    public void setAddressID(int addressID) {
        if (m_nullable)
            throw new UnsupportedOperationException(NULL_EXCEPTION);
        this.m_addressID = addressID;
    }

    public int getPersonID() {
        return m_personID;
    }

    public void setPersonID(int personID) {
        if (m_nullable)
            throw new UnsupportedOperationException(NULL_EXCEPTION);
        this.m_personID = personID;
    }

    public String getAddress() {
        return m_address;
    }

    public void setAddress(String address) {
        if (m_nullable)
            throw new UnsupportedOperationException(NULL_EXCEPTION);

        this.m_address = (address.length() > ADDRESS_LENGTH) ? address.substring(0, ADDRESS_LENGTH - 1) : address;
    }

    private int m_addressID;
    private int m_personID;
    private String m_address;
    private boolean m_nullable;
}
